/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.utx.spot.timesync.protocol;

// import com.sun.spot.peripheral.NoRouteException;
import com.sun.spot.peripheral.TimeoutException;
import com.sun.spot.io.j2me.radiogram.*;
import com.sun.squawk.VM;

import java.io.IOException;
import javax.microedition.io.*;


/**
 * 
 */
public class TimeServer {

    private RadiogramConnection broadcastConnection;
    private RadiogramConnection serverConnection;

    private byte syncID = 0;
    private byte syncLevel = 0;

    private final int SYNC_PERIOD_MS = 10000;

    public TimeServer() throws IOException {
        broadcastConnection = (RadiogramConnection) Connector.open("radiogram://broadcast:40");
        serverConnection = (RadiogramConnection) Connector.open("radiogram://:41");

        // sync messages are only useful to the nodes within the broadcast range
        broadcastConnection.setMaxBroadcastHops(1);
        startServerThread();
    }

    private void startServerThread() {
        Thread serverThread = new Thread() {
            public void run() {
                System.out.println("[server] starting timesync");
                while (true) {
                    try {
                        sendSyncBroadcast();
                        receiveDelayRequests();
                    }
                    catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        VM.setAsDaemonThread(serverThread);
        serverThread.start();
    }


    private void sendSyncBroadcast() throws IOException {
        final int size = broadcastConnection.getMaximumLength();
        System.out.println("[server] send sync broadcast");
        Radiogram syncMsg = (Radiogram) broadcastConnection.newDatagram(size);
        syncMsg.writeByte(0x1);
        syncMsg.writeByte(syncID);
        syncMsg.writeByte(syncLevel);
        broadcastConnection.send(syncMsg);

        final long syncTxTimestamp = syncMsg.getSyncTimestamp();

        syncMsg.reset();
        syncMsg.writeByte(0x3);
        syncMsg.writeByte(syncID);
        syncMsg.writeByte(syncLevel);
        syncMsg.writeLong(syncTxTimestamp);
        broadcastConnection.send(syncMsg);
        
        syncID += 1;
        
        System.out.println("[server] sync tx timestamp = " + syncTxTimestamp);
    }

    private void receiveDelayRequests() throws IOException {
        final int size = serverConnection.getMaximumLength();
        final long startTime = System.currentTimeMillis();
        int timeRemaining = SYNC_PERIOD_MS;
        while(timeRemaining > 0) {
            
            serverConnection.setTimeout(timeRemaining);
            Radiogram delayRequest = (Radiogram) serverConnection.newDatagram(size);
            try {
                serverConnection.receive(delayRequest);
            }
            catch (TimeoutException e) {
               System.out.println("[server] delay request timeout.");
               return;
            }

            if (delayRequest.readByte() == 0x10) {
                // got a delay request, send back the RX timestamp
                final byte requestID = delayRequest.readByte();
                final long requestRxTimestamp = delayRequest.getSyncTimestamp();
                Radiogram delayReply = (Radiogram) serverConnection.newDatagram(size);
                delayReply.setAddress(delayRequest);
                delayReply.writeByte(0x30);
                delayReply.writeByte(requestID);
                delayReply.writeLong(requestRxTimestamp);
                serverConnection.send(delayReply);
                
                System.out.println("[server] delay request from " + delayRequest.getAddress());
                System.out.println("[server] rx timestamp = " + requestRxTimestamp);
            }
            
            timeRemaining = SYNC_PERIOD_MS - (int)(System.currentTimeMillis() - startTime);
        }
    }
}
